#include "EditorDragableSpinWidget.h"
#include "Framework/Application.h"
#include "Font/FontSubsystem.h"
#include "Render/Widget/RenderWidgets.h"
#include "Platform/PlatformInterface.h"
#include "Widgets/Window.h"


static float ValueBeforeDrag=0;

REditorDragableSpinWidget::REditorDragableSpinWidget()
{
    Mouse=NewWidget<RMouseWidget>(this);
    Mouse->Anchor.Fill(this);
    Mouse->CursorShape=[this]()->EMouseCursorType
    {   
        //update bCanDrag 
        if(!bIsEditing)
        {
            this->bCanDrag=true;
        }
        else
        {
            auto MousePosition=Mouse->GetMousePositionInWidget();
            const float BeamPadding=3;
            if(MousePosition.Y<BeamPadding
                ||MousePosition.Y>PresentSize.Y-BeamPadding)
            {
                this->bCanDrag=true;
            }
            else
            {
                this->bCanDrag=false;
            }
        }


        if(this->bCanDrag)
        {
            return EMouseCursorType::ResizeHorizontal;
        }
        else
        {
            return EMouseCursorType::IBeam;
        }
    };
    Mouse->Drag->bIsEnabled=[this]()->bool
    {
        return this->bCanDrag;
    };
    Mouse->Drag->OnDragStarted.Bind([this]()
    {
        Accept(); //exit edit mode
        bDragging=true;
        ValueBeforeDrag=Value.Get();
        this->GetWindow()->StartCaptureMouse();
    });
    Mouse->Drag->OnDragMoved.Bind([this](const SVec2& InTotalDistance)
    {
        float NewValue=ValueBeforeDrag+InTotalDistance.X*Step.Get();
        if(NewValue>MaxValue.Get())
        {
            NewValue=MaxValue.Get();
        }
        if(NewValue<MinValue.Get())
        {
            NewValue=MinValue.Get();
        }
        
        OnAccepted.Broadcast(ETextEditStopReason::Accept,NewValue);
    });
    Mouse->Drag->OnDragEnded.Bind([this]()
    {
        bDragging=false;
        this->GetWindow()->StopCaptureMouse();
    });


    Keyboard=NewWidget<RKeyboardWidget>(this);
    Keyboard->Anchor.Fill(this);
    Mouse->AutoFocusTarget=Keyboard;
    //Mouse->bAutoFocusConsumesEvent=false;
    Keyboard->OnKeyboardFocused.Bind(this,&REditorDragableSpinWidget::OnFocused);
    Keyboard->OnKeyboardUnfocused.Bind(this,&REditorDragableSpinWidget::OnUnfocused);
    Keyboard->OnTextInput.Bind(this,&REditorDragableSpinWidget::ProcessTextInput);
    Keyboard->OnKeyboardInput.Bind(this,&REditorDragableSpinWidget::ProcessKeyInput);

    RMouseWidgetWeakPtr MouseWeak=Mouse;
    Mouse->OnClicked.BindLambda([this,MouseWeak](const SMouseButtonEvent &)->bool
    {
        //计算光标位置
        auto MousePosition=this->GetMousePositionInWidget();
        CursorPosition= TextArranger.GetArrangeResult().CalculateCursorIndex(MousePosition);
        return true;
    }); 

}

void REditorDragableSpinWidget::StartEdit()
{
    Keyboard->Focus();
}

void REditorDragableSpinWidget::Accept()
{
    if(bIsEditing)
    {
        bIsEditing=false;
        Keyboard->Unfocus();
        OnAccepted.Broadcast(ETextEditStopReason::Accept,EditingString.ToDouble());
    }
}

void REditorDragableSpinWidget::CancelEdit()
{
    if(bIsEditing)
    {
        bIsEditing=false;
        Keyboard->Unfocus();
        OnAccepted.Broadcast(ETextEditStopReason::Cancel,EditingString.ToDouble());
    }
}

bool REditorDragableSpinWidget::IsEditing()
{
    return bIsEditing;
}

bool REditorDragableSpinWidget::IsHovered()
{
    return Mouse->IsHovered();
}

void REditorDragableSpinWidget::PaintSelf(uint16_t &InZOrder, const SRect &InClipArea)
{
    //paint text
    bool PaintText=TextArranger.GetArrangeResult().GetRenderCharCount()>0;
    if(PaintText)
    {
        // auto RenderTextWidget=std::make_shared<SRenderStaticTextWidget>();
        // RenderTextWidget->Rect= SRect(
        //     TextArranger.GetArrangeResult().WholeImageOffset+PresentAbsPosition
        //     ,TextArranger.GetArrangeResult().WholeImageSize
        // );
        // RenderTextWidget->ClipRect=InClipArea;
        // RenderTextWidget->ZOrder=InZOrder;

        // RenderTextWidget->TextImage=TextArranger.GetArrangeResult().WholeImage->GetRenderTexture();
        // RenderTextWidget->TextColor= Color.Get();

        auto RenderTextWidget=std::make_shared<SRenderStaticTextWidget>();
        RenderTextWidget->Rect=SRect(PresentAbsPosition,PresentSize);
        RenderTextWidget->ClipRect=InClipArea;
        RenderTextWidget->ZOrder=InZOrder;
        InZOrder++;

        RenderTextWidget->TextColor= Color.Get();
        RenderTextWidget->CharTextures=TextArranger.GetArrangeResult().GetRenderCharTextures();
        RenderTextWidget->CharPositions=TextArranger.GetArrangeResult().GetCharPositions();

        PaintRenderWidget(RenderTextWidget);
    }

    //paint cursor
    bool PaintCursor=bIsEditing&&bShowCursor;
    if(PaintCursor)
    {
        auto Cursor=std::make_shared<SRenderRectWidget>();
        Cursor->bFill=true;
        Cursor->FillColor=CursorColor.Get();
        Cursor->ZOrder=InZOrder;
        Cursor->ClipRect=InClipArea;

        //计算光标矩形
        auto CursorRect=TextArranger.GetArrangeResult().CalculateCursorRect(CursorPosition,CursorWidth.Get());
        CursorRect.Min+=PresentAbsPosition;
        Cursor->Rect=CursorRect;
        PaintRenderWidget(Cursor);
    }

    if(PaintText||PaintCursor)
    {
        InZOrder++;
    }

}

void REditorDragableSpinWidget::CalculatePresentPositionAndSize()
{
    Super::CalculatePresentPositionAndSize();
    ArrangeGlyphs();

}

void REditorDragableSpinWidget::ArrangeGlyphs()
{
    STextArrangePapameters Params;
    Params.Font=GetRenderingFont();
    Params.FontSize=FontSize.Get();
    if(bIsEditing)
    {
        Params.Text=EditingString;
    }
    else
    {
        float _Value=Value.Get();
        if(IsInteger.Get())
        {
            Params.Text=CString((int64_t)_Value);
        }
        else
        {
            Params.Text=CString(_Value);
        }
    }
    Params.Wrap=ETextWrapMethod::None;
    Params.HorizontalAlign=HorizontalAlignment.Get();
    Params.VerticalAlign=VerticalAlignment.Get();
    Params.PaintAreaSize=PresentSize;

    TextArranger.ArrangeText(Params);

}

void REditorDragableSpinWidget::OnFocused()
{
    bIsEditing=true;
    if(IsInteger.Get())
    {
        EditingString=CString((int64_t)Value.Get());
    }
    else
    {
        EditingString=CString(Value.Get());
    }
    ForceShowCursor();

    IPlatformInterface::GetPlatformInterface()->StartTextInput(
        GetWindow()->GetWindowID()
        ,GetWindow()->ContentSpaceToWindowSpace(
            SIntPoint(
                PresentAbsPosition.X
                ,PresentAbsPosition.Y+PresentSize.Y
            )
        )
    );
}

void REditorDragableSpinWidget::OnUnfocused()
{
    if(bIsEditing)
    {
        bIsEditing=false;
        OnAccepted.Broadcast(ETextEditStopReason::LostFocus,EditingString.ToDouble());
    }
    HideCursor();

    IPlatformInterface::GetPlatformInterface()->StopTextInput();
}

bool REditorDragableSpinWidget::ProcessTextInput(const STextInputEvent &InEvent)
{
    assert(bIsEditing);

    CString InputText=InEvent.GetInputText();

    //filter invalid char
    bool bIsInteger=IsInteger.Get();
    CString ValidText;
    for(int64_t i=0;i<InputText.GetLength();i++)
    {
        if((InputText[i]>=U'0'&&InputText[i]<=U'9')||
            ((!bIsInteger) && InputText[i]==U'.'))
        {
            ValidText+=InputText[i];
        }
    }
    
    if(ValidText.IsEmpty())
    {
        return true;
    }

    if(CursorPosition==EditingString.GetLength()-1)
    {
        EditingString+=ValidText;
    }
    else
    {
        EditingString=EditingString.Insert(CursorPosition+1,ValidText);
    }
    CursorPosition+=InputText.GetLength();
    ForceShowCursor();

    return true;
}

bool REditorDragableSpinWidget::ProcessKeyInput(const SKeyboardEvent & BoardkeyEvent)
{
    if(!bIsEditing)
    {
        return false;
    }

    if(BoardkeyEvent.KeyState!=EKeyState::Pressed)
    {
        return false;
    }

    switch(BoardkeyEvent.Key)
    {
        case EKey::Left:
        {
            if(CursorPosition>-1)
            {
                CursorPosition--;
            }
            ForceShowCursor();
            break;
        }

        case EKey::Right:
        {
            if(CursorPosition<EditingString.GetLength()-1)
            {
                CursorPosition++;
            }
            ForceShowCursor();
            break;
        }

        case EKey::Backspace:
        {
            if(CursorPosition>-1)
            {
                EditingString=EditingString.RemoveAt(CursorPosition,1);
                CursorPosition--;
            }
            ForceShowCursor();
            break;
        }

        case EKey::Enter:
        {
            Accept();
            break;
        }

        case EKey::Escape:
        {
            CancelEdit();
            break;
        }
    }

    return true;
}

void REditorDragableSpinWidget::ForceShowCursor()
{
    bShowCursor=true;
    CursorTime=0;
}

void REditorDragableSpinWidget::HideCursor()
{
    bShowCursor=false;
    CursorTime=0;
}

TSharedObjectPtr<RFont> REditorDragableSpinWidget::GetRenderingFont()
{
    if(Font.IsValid())
    {
        return Font.Get();
    }
    else
    {
        return RApplication::GetApplication()->GetSubsystem<RFontApplicationSubsystem>()->GetDefaultFont();
    }
}

void REditorDragableSpinWidget::Tick(float DeltaSeconds)
{
    if(bIsEditing)
    {
        CursorTime+=DeltaSeconds;
        if(CursorTime>CursorBlinkTime)
        {
            CursorTime-=CursorBlinkTime;
            bShowCursor=!bShowCursor;
        }
    }

    Super::Tick(DeltaSeconds);
}
